#include "DeferredShading.h"


DeferredShading::DeferredShading (int w, int h) :
width (w), height (h),
gBufferID (100), gBufferTexID ()
{   
   quadData = new glm::vec4[4];
   quadData[0] = glm::vec4 (-1.0f, -1.0f, 0.5f, 1.0f);
   quadData[1] = glm::vec4 ( 1.0f, -1.0f, 0.5f, 1.0f);
   quadData[2] = glm::vec4 (-1.0f,  1.0f, 0.5f, 1.0f);
   quadData[3] = glm::vec4 ( 1.0f,  1.0f, 0.5f, 1.0f);
}
void DeferredShading::initGBuffer ()
{
   glGenVertexArrays (1, &vaoID);
   glBindVertexArray (vaoID);
   
   //Quad
   glGenBuffers (1, &quadID);
   glBindBuffer (GL_ARRAY_BUFFER, quadID);
   glBufferData (GL_ARRAY_BUFFER, 4 * sizeof(glm::vec4), quadData, GL_STATIC_DRAW);
   glEnableVertexAttribArray (0);
   glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), NULL);
   delete[] quadData;
   glBindVertexArray (0);

   //FBO
   glGenFramebuffers (1, &gBufferID);
   glBindFramebuffer (GL_FRAMEBUFFER, gBufferID);

   glGenTextures (3, gBufferTexID);

   glBindTexture (GL_TEXTURE_2D, gBufferTexID[0]);
   glTexStorage2D (GL_TEXTURE_2D, 1, GL_RGBA32UI, width, height);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

   glBindTexture (GL_TEXTURE_2D, gBufferTexID[1]);
   glTexStorage2D (GL_TEXTURE_2D, 1, GL_RGBA32F, width, height);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

   glBindTexture (GL_TEXTURE_2D, gBufferTexID[2]);
   glTexStorage2D (GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT32F, width, height);

   glFramebufferTexture (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gBufferTexID[0], 0);
   glFramebufferTexture (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, gBufferTexID[1], 0);
   glFramebufferTexture (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, gBufferTexID[2], 0);

   glBindFramebuffer (GL_FRAMEBUFFER, 0);
}
void DeferredShading::renderToGBuffer ()
{
   static const GLuint      uiZeros[] = {0, 0, 0, 0};
   static const GLfloat      fZeros[] = {0.0f, 0.0f, 0.0f, 0.0f};
   static const GLfloat       fOnes[] = {1.0f, 1.0f, 1.0f, 1.0f};
   static const GLenum draw_buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};

   glBindFramebuffer (GL_FRAMEBUFFER, gBufferID);
   glViewport (0, 0, width, height);
   glDrawBuffers (2, draw_buffers);
   glClearBufferuiv (GL_COLOR, 0, uiZeros);
   glClearBufferfv (GL_COLOR, 1, fZeros);
   glClearBufferfv (GL_DEPTH, 0, fOnes);
   glEnable (GL_DEPTH_TEST);
   glDepthFunc (GL_LEQUAL);

}

void DeferredShading::renderFromGBuffer ()
{
   glBindFramebuffer (GL_FRAMEBUFFER, 0);
   glViewport (0, 0, width, height);
   glDrawBuffer (GL_BACK);

   glActiveTexture (GL_TEXTURE0);
   glBindTexture (GL_TEXTURE_2D, gBufferTexID[0]);

   glActiveTexture (GL_TEXTURE1);
   glBindTexture (GL_TEXTURE_2D, gBufferTexID[1]);
   glDisable (GL_DEPTH_TEST);
   drawQuad ();
   glBindTexture (GL_TEXTURE_2D, 0);
   glActiveTexture (GL_TEXTURE0);
   glBindTexture (GL_TEXTURE_2D, 0);
}

void DeferredShading::drawQuad ()
{
   glBindVertexArray (vaoID);
   glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
   glBindVertexArray (0);
}
DeferredShading::~DeferredShading ()
{
}
